package com.blank.shop.ssr.config;

import io.rebloom.client.Client;
import org.apache.commons.lang3.StringUtils;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;

import javax.annotation.Resource;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;

/**
 * <br/>Date 2021/9/2
 * <br/>Time 18:39:07
 *
 * @author _blank
 */
@Configuration
@AutoConfigureAfter(value = {RedisAutoConfiguration.class, RedissonAutoConfiguration.class})
public class RedisConfig implements InitializingBean, Ordered, SmartInitializingSingleton {

    @Resource
    private RedisTemplate<Object, Object> redisTemplate;

    @Override
    public void afterPropertiesSet() throws Exception {
        this.redisTemplate.setKeySerializer(RedisSerializer.string());
        this.redisTemplate.setValueSerializer(RedisSerializer.json());

        this.redisTemplate.setHashKeySerializer(RedisSerializer.string());
        this.redisTemplate.setHashValueSerializer(RedisSerializer.json());
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    @Override
    public void afterSingletonsInstantiated() {
    }

    @Bean
    public Client rebloomClient(RedisProperties properties) {
        final RedisProperties.Sentinel sentinel = properties.getSentinel();
        if (Objects.nonNull(sentinel)) {
            final String masterName = sentinel.getMaster();
            final Set<String> sentinels = new LinkedHashSet<>(sentinel.getNodes());

            final JedisPoolConfig poolConfig = new JedisPoolConfig();
            final RedisProperties.Pool jedisPoolProperties = properties.getJedis().getPool();
            if (Objects.nonNull(jedisPoolProperties)) {
                poolConfig.setMaxTotal(jedisPoolProperties.getMaxActive());
                poolConfig.setMaxIdle(jedisPoolProperties.getMaxIdle());
                poolConfig.setMinIdle(jedisPoolProperties.getMinIdle());
                if (jedisPoolProperties.getTimeBetweenEvictionRuns() != null) {
                    poolConfig.setTimeBetweenEvictionRunsMillis(jedisPoolProperties.getTimeBetweenEvictionRuns().toMillis());
                }
                if (jedisPoolProperties.getMaxWait() != null) {
                    poolConfig.setMaxWaitMillis(jedisPoolProperties.getMaxWait().toMillis());
                }
            }

            final int connectionTimeout = Objects.nonNull(properties.getTimeout()) ? (int) properties.getTimeout().toMillis() : 0;
            final int soTimeout = Objects.nonNull(properties.getTimeout()) ? (int) properties.getTimeout().toMillis() : 0;
            final String user = null;
            final String password = StringUtils.defaultString(properties.getPassword(), null);
            final int database = properties.getDatabase();
            final String clientName = StringUtils.defaultString(properties.getClientName(), null);

            final int sentinelConnectionTimeout = 0;
            final int sentinelSoTimeout = 0;
            final String sentinelUser = null;
            final String sentinelPassword = null;
            final String sentinelClientName = null;

            final JedisSentinelPool pool = new JedisSentinelPool(masterName
                    , sentinels
                    , poolConfig
                    , connectionTimeout
                    , soTimeout
                    , user
                    , password
                    , database
                    , clientName
                    , sentinelConnectionTimeout
                    , sentinelSoTimeout
                    , sentinelUser
                    , sentinelPassword
                    , sentinelClientName
            );
            return new Client(pool);
        }
        throw new UnsupportedOperationException("未实现，请检查！");
    }

}
